﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using System.Diagnostics.Contracts;
using System.Diagnostics;
using Microsoft.Practices.ServiceLocation;

namespace AzureToolkit.Engine
{
    public class CloudEngine
    {

        private List<Action> runActions;

        protected CloudEngineSettings Settings { get; private set; }

        public CloudEngine()
        {
            Settings = new CloudEngineSettings();
            runActions = new List<Action>();
        }

        public void Setup(Action<CloudEngineSettings> config)
        {
            Contract.Requires(config != null);
            config(Settings);
        }

        public void WithMessageHandler<TMessage, TCommand>(Action<MessageHandlerSettings> config)
            where TMessage : IAzureQueueMessage
            where TCommand : ICommandBase<TMessage>
        {

            var settings = new MessageHandlerSettings(this.Settings);
            settings.CommandType = typeof(TCommand);
            config(settings);

            IMessageHandler messageHandler = null;
            if (settings.CommandType.GetInterfaces().Any(x =>
                    x.IsGenericType &&
                    x.GetGenericTypeDefinition() == typeof(IBatchCommand<>)))
            {
                messageHandler = new BatchMessageHandler<TMessage>(settings);
            }
            else if (settings.CommandType.GetInterfaces().Any(x =>
                    x.IsGenericType &&
                    x.GetGenericTypeDefinition() == typeof(ICommand<>)))
            {
                messageHandler = new MessageHandler<TMessage>(settings);
            }
            else if (settings.CommandType.GetInterfaces().Any(x =>
                  x.IsGenericType &&
                  x.GetGenericTypeDefinition() == typeof(IBatchTransactionalCommand<>)))
            {
                messageHandler = new BatchTransactionalMessageHandler<TMessage>(settings);
            }

            if (messageHandler == null)
            {
                throw new InvalidOperationException("Message handler is null.");
            }
            messageHandler.Initialize();

            runActions.Add(messageHandler.Run);
        }

        public JobSchedulingProcessFluent WithJobScheduler()
        {
            return WithJobScheduler(null);
        }

        public JobSchedulingProcessFluent WithJobScheduler(Action<JobSchedulingSettings> config)
        {
            var settings = new JobSchedulingSettings(this.Settings);
            if (config != null)
            {
                config(settings);
            }
            var scheduler = new JobSchedulingProcess(settings);
            scheduler.Initialize();
            runActions.Add(scheduler.Run);

            var runner = new JobRunnerProcess(settings);
            runner.Initialize();
            runActions.Add(runner.Run);

            return new JobSchedulingProcessFluent(scheduler);
        }

        public void Run()
        {
            if (ServiceLocator.Current == null)
            {
                throw new InvalidOperationException("ServiceLocator.Current must be set before running the cloud engine. See: http://commonservicelocator.codeplex.com/");
            }

            foreach (var runAction in runActions)
            {
                try
                {
                    runAction.Invoke();
                }
                catch
                {
                    Trace.TraceError("Error invoking run action.");
                }
            }
        }
    }
}
